package org.cloudplatform.common.test.curator;

import lombok.extern.slf4j.Slf4j;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.imps.CuratorFrameworkState;
import org.apache.curator.framework.recipes.cache.CuratorCache;
import org.apache.curator.framework.recipes.cache.CuratorCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.junit.Before;
import org.junit.Test;

/**
 * 类描述：
 * 作者：徐卫超 (cc)
 * 时间 2022/5/16 16:49
 */
@Slf4j
public class CuratorCacheListenerDemo {
    CuratorFramework curator;

    private static final String SERVER_PROXY = "192.168.101.22:2181";
    private static final int CONNECTION_TIMEOUT_MS = 3000;
    private static final int SESSION_TIMEOUT_MS = 1000;
    private static final String NAMESPACE = "MyNamespace";

    @Before
    public void init() {
        System.setProperty("zookeeper.sasl.client", "false");
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        // 创建CuratorFramework实例
        this.curator = CuratorFrameworkFactory.builder()
                .connectString(SERVER_PROXY)
                .retryPolicy(retryPolicy)
                .connectionTimeoutMs(CONNECTION_TIMEOUT_MS)
                .sessionTimeoutMs(SESSION_TIMEOUT_MS)
                .namespace(NAMESPACE)
                .build();

        this.curator.start();
    }

    @Test
    public void curatorCacheDemo() throws Exception {
        // 重试策略
        assert curator.getState().equals(CuratorFrameworkState.STARTED);
        curator.blockUntilConnected();

        if (curator.checkExists().forPath("/father") != null) {
            curator.delete().deletingChildrenIfNeeded().forPath("/father");
        }

        // 创建CuratorCache实例，基于路径/father/son/grandson1（这里说的路径都是基于命名空间下的路径）
        // 缓存构建选项是SINGLE_NODE_CACHE
        CuratorCache cache = CuratorCache.build(curator, "/father/son/grandson1",
                CuratorCache.Options.SINGLE_NODE_CACHE);

        // 创建一系列CuratorCache监听器，都是通过lambda表达式指定
        CuratorCacheListener listener = CuratorCacheListener.builder()
                // 初始化完成时调用
                .forInitialized(() -> System.out.println("[forInitialized] : Cache initialized"))
                // 添加或更改缓存中的数据时调用
                .forCreatesAndChanges((oldNode, node) -> {
                    log.info("forCreatesAndChanges {} \t  Data: {}", node.getPath(), new String(node.getData()));
                })
                // 添加缓存中的数据时调用
                .forCreates(childData -> {
                    log.info("forCreates {} \t  Data: {}", childData.getPath(), new String(childData.getData()));
                })
                // 更改缓存中的数据时调用
                .forChanges((oldNode, node) -> {
                    log.info("forChanges {} \t  Data: {}", node.getPath(), new String(node.getData()));
                })
                // 删除缓存中的数据时调用
                .forDeletes(childData -> {
                    log.info("forDeletes {} \t  Data: {}", childData.getPath(), new String(childData.getData()));
                })
                // 添加、更改或删除缓存中的数据时调用
                .forAll((type, oldData, data) -> {
                    log.info("forAll type:{} \t {} \t  Data: {}", type, data.getPath(), new String(data.getData()));
                })
                .build();

        // 给CuratorCache实例添加监听器
        cache.listenable().addListener(listener);

        // 启动CuratorCache
        cache.start();

        // 创建节点/father/son/grandson1
        curator.create()
                .creatingParentsIfNeeded()
                .withMode(CreateMode.PERSISTENT)
                .forPath("/father/son/grandson1", "step1".getBytes());

        // 创建节点/father/son/grandson1/test
        curator.create()
                .creatingParentsIfNeeded()
                .withMode(CreateMode.PERSISTENT)
                .forPath("/father/son/grandson1/test", "step2".getBytes());

        // 更改节点/father/son/grandson1的数据
        curator.setData()
                .forPath("/father/son/grandson1", "step5".getBytes());


        log.info("创建完毕");
//        // 删除节点/father/son/grandson1
//        curator.delete()
//                .deletingChildrenIfNeeded()
//                .forPath("/father/son/grandson1");

        Thread.sleep(10000000);
    }


}
